﻿using TMPro;
using UnityEngine;
using UnityEngine.UI;

namespace HEFramework
{
    public static class HeroInfoUISystem
    {
        [EntitySystem]
        public class HeroInfoUIAwakeSystem : AwakeSystem<HeroInfoUI>
        {
            protected override void Awake(HeroInfoUI _self)
            {
                _self.AddChild<UnityObjectComponent>();
            }
        }


        [EntitySystem]
        public class HeroInfoUIUpdateSystem : UpdateSystem<HeroInfoUI>
        {
            protected override void Update(HeroInfoUI _self)
            {
                _self.Update();
            }
        }


        [EntitySystem]
        public class HeroInfoUIDestroySystem : DestroySystem<HeroInfoUI>
        {
            protected override void Destroy(HeroInfoUI _self)
            {
                _self.Close();
            }
        }

        public static void Open(this HeroInfoUI _self)
        {
            var uc = _self.GetSceneChild<UIComponent>();
            if (uc == null)
            {
                return;
            }

            uc.PushUIAsync(eUIFlag.HeroInfo, _ =>
            {
                _self.UIWindowBehaviour = _;
                _self.Bind();
                _self.Update(true);
            });
        }

        public static void Bind(this HeroInfoUI _self)
        {
            if (_self.UIWindowBehaviour == null)
            {
                return;
            }

            var dc = _self.GetSceneChild<DataTableComponent>();
            if (dc == null)
            {
                return;
            }

            _self.UIWindowBehaviour.GetButton("Button_Back").RegisterUpEvent(_self.Close);
        }

        public static void Update(this HeroInfoUI _self, bool _isNew = false)
        {
            if (_self.UIWindowBehaviour == null || _self.UIWindowBehaviour.State == 0)
            {
                return;
            }

            if (_isNew)
            {
                _self.UpdateHeroAttribute(_isNew);
                _self.UpdateHeroSkill(_isNew);
                return;
            }

            _self.RefreshTime -= Time.deltaTime;
            if (_self.RefreshTime <= 0)
            {
                _self.RefreshTime = 0.5f;
                _self.UpdateHeroAttribute(_isNew);
                _self.UpdateHeroSkill(_isNew);
            }
        }

        public static void Close(this HeroInfoUI _self)
        {
            if (_self.UIWindowBehaviour == null)
            {
                return;
            }

            _self.UIWindowBehaviour.Hide();
            _self.UIWindowBehaviour = null;
        }

        private static void UpdateHeroAttribute(this HeroInfoUI _self, bool _isNew)
        {
            var uc = _self.GetChild<UnityObjectComponent>();
            if (uc == null)
            {
                return;
            }

            var scroll_view = _self.UIWindowBehaviour.GetScrollView("ScrollView_ScrollViewItem");
            int length = 24;
            if (_isNew)
            {
                scroll_view.RowCount = 0;
                scroll_view.ItemCallback = (_behaviour, _index) => { uc.Get<TMP_Text>(_behaviour.GameObject).text = _self.GetAttributeText(_index); };
                scroll_view.RowCount = length;
            }
            else
            {
                scroll_view.Refresh(0, length);
            }
        }

        private static string GetAttributeText(this HeroInfoUI _self, int _index)
        {
            var teamUI = _self.GetSceneChild<TeamUI>();
            var team = _self.GetSceneChild<Team>();
            var dc = _self.GetSceneChild<DataTableComponent>();
            if (teamUI == null || team == null || dc == null)
            {
                return "";
            }

            var attribute_table = dc.LoadDataTable<DRAttribute>();
            var language_table = dc.LoadDataTable<DRLanguage>();
            var level_table = dc.LoadDataTable<DRLevel>();

            var attribute_data = attribute_table.GetData(teamUI.SelectID);
            var level_data = level_table.GetData(attribute_data.LV_ID);
            var hero = team.GetHero(attribute_data.ID);
            var ac = hero.GetChild<AttributeComponent>();

            string empty = " ";
            string colon = ":";
            string backslash = "/";
            string second = "s";
            string add = "+";
            string cut = "-";
            string pct = "%";

            _self.StringBuilder.Clear();

            switch (_index)
            {
                case 0:
                    _self.StringBuilder.Append(language_table.GetData(122).Text);
                    _self.StringBuilder.Append(colon);
                    _self.StringBuilder.Append(empty);
                    _self.StringBuilder.Append(attribute_data.Name);
                    return _self.StringBuilder.ToString();
                case 1:
                    _self.StringBuilder.Append(language_table.GetData(123).Text);
                    _self.StringBuilder.Append(colon);
                    _self.StringBuilder.Append(empty);
                    _self.StringBuilder.Append(ac.LV);
                    return _self.StringBuilder.ToString();
                case 2:
                    _self.StringBuilder.Append(language_table.GetData(124).Text);
                    _self.StringBuilder.Append(colon);
                    _self.StringBuilder.Append(empty);
                    _self.StringBuilder.Append(ac.RANK);
                    return _self.StringBuilder.ToString();
                case 3:
                    _self.StringBuilder.Append(language_table.GetData(125).Text);
                    _self.StringBuilder.Append(colon);
                    _self.StringBuilder.Append(empty);
                    _self.StringBuilder.Append((int)ac.EXP);
                    _self.StringBuilder.Append(backslash);
                    _self.StringBuilder.Append(level_data.Exps[ac.LV]);
                    return _self.StringBuilder.ToString();
                case 4:
                    _self.StringBuilder.Append(language_table.GetData(100).Text);
                    _self.StringBuilder.Append(colon);
                    _self.StringBuilder.Append(empty);
                    _self.StringBuilder.Append((int)ac.HP);
                    _self.StringBuilder.Append(backslash);
                    _self.StringBuilder.Append(ac.X_HP.Value);
                    return _self.StringBuilder.ToString();
                case 5:
                    _self.StringBuilder.Append(language_table.GetData(101).Text);
                    _self.StringBuilder.Append(colon);
                    _self.StringBuilder.Append(empty);
                    _self.StringBuilder.Append((int)ac.MP);
                    _self.StringBuilder.Append(backslash);
                    _self.StringBuilder.Append((int)ac.X_MP.Value);
                    return _self.StringBuilder.ToString();
                case 6:
                    _self.StringBuilder.Append(language_table.GetData(102).Text);
                    _self.StringBuilder.Append(colon);
                    _self.StringBuilder.Append(empty);
                    _self.StringBuilder.Append((int)ac.P_ATK.Value);
                    return _self.StringBuilder.ToString();
                case 7:
                    _self.StringBuilder.Append(language_table.GetData(115).Text);
                    _self.StringBuilder.Append(colon);
                    _self.StringBuilder.Append(empty);
                    _self.StringBuilder.Append((int)ac.M_ATK.Value);
                    return _self.StringBuilder.ToString();
                case 8:
                    _self.StringBuilder.Append(language_table.GetData(103).Text);
                    _self.StringBuilder.Append(colon);
                    _self.StringBuilder.Append(empty);
                    _self.StringBuilder.Append((int)ac.P_DEF.Value);
                    return _self.StringBuilder.ToString();
                case 9:
                    _self.StringBuilder.Append(language_table.GetData(104).Text);
                    _self.StringBuilder.Append(colon);
                    _self.StringBuilder.Append(empty);
                    _self.StringBuilder.Append((int)Formula.MDEF(ac.M_DEF));
                    return _self.StringBuilder.ToString();
                case 10:
                    _self.StringBuilder.Append(language_table.GetData(130).Text);
                    _self.StringBuilder.Append(colon);
                    _self.StringBuilder.Append(empty);
                    _self.StringBuilder.Append((int)ac.REC_HP.Value);
                    return _self.StringBuilder.ToString();
                case 11:
                    _self.StringBuilder.Append(language_table.GetData(131).Text);
                    _self.StringBuilder.Append(colon);
                    _self.StringBuilder.Append(empty);
                    _self.StringBuilder.Append((int)ac.REC_MP.Value);
                    return _self.StringBuilder.ToString();
                case 12:
                    _self.StringBuilder.Append(language_table.GetData(105).Text);
                    _self.StringBuilder.Append(colon);
                    _self.StringBuilder.Append(empty);
                    _self.StringBuilder.Append((int)ac.P_ATK_SP.Value);
                    return _self.StringBuilder.ToString();
                case 13:
                    _self.StringBuilder.Append(language_table.GetData(106).Text);
                    _self.StringBuilder.Append(colon);
                    _self.StringBuilder.Append(empty);
                    _self.StringBuilder.Append((int)Formula.M_ATK_SP(ac.M_ATK_SP));
                    return _self.StringBuilder.ToString();
                case 14:
                    _self.StringBuilder.Append(language_table.GetData(126).Text);
                    _self.StringBuilder.Append(colon);
                    _self.StringBuilder.Append(empty);
                    _self.StringBuilder.Append((int)ac.P_ATK_RAG);
                    return _self.StringBuilder.ToString();
                case 15:
                    _self.StringBuilder.Append(language_table.GetData(107).Text);
                    _self.StringBuilder.Append(colon);
                    _self.StringBuilder.Append(empty);
                    _self.StringBuilder.Append((int)Formula.DOGV(ac.DOG));
                    return _self.StringBuilder.ToString();
                case 16:
                    _self.StringBuilder.Append(language_table.GetData(127).Text);
                    _self.StringBuilder.Append(colon);
                    _self.StringBuilder.Append(empty);
                    _self.StringBuilder.Append((int)ac.TRT);
                    return _self.StringBuilder.ToString();
                case 17:
                    _self.StringBuilder.Append(language_table.GetData(110).Text);
                    _self.StringBuilder.Append(colon);
                    _self.StringBuilder.Append(empty);
                    _self.StringBuilder.Append((int)ac.P_CRT);
                    _self.StringBuilder.Append(pct);
                    return _self.StringBuilder.ToString();
                case 18:
                    _self.StringBuilder.Append(language_table.GetData(111).Text);
                    _self.StringBuilder.Append(colon);
                    _self.StringBuilder.Append(empty);
                    _self.StringBuilder.Append((int)ac.M_CRT);
                    _self.StringBuilder.Append(pct);
                    return _self.StringBuilder.ToString();
                case 19:
                    _self.StringBuilder.Append(language_table.GetData(112).Text);
                    _self.StringBuilder.Append(colon);
                    _self.StringBuilder.Append(empty);
                    _self.StringBuilder.Append((int)ac.P_CRT_ADD);
                    _self.StringBuilder.Append(pct);
                    return _self.StringBuilder.ToString();
                case 20:
                    _self.StringBuilder.Append(language_table.GetData(113).Text);
                    _self.StringBuilder.Append(colon);
                    _self.StringBuilder.Append(empty);
                    _self.StringBuilder.Append((int)ac.M_CRT_ADD);
                    _self.StringBuilder.Append(pct);
                    return _self.StringBuilder.ToString();
                case 21:
                    _self.StringBuilder.Append(language_table.GetData(108).Text);
                    _self.StringBuilder.Append(colon);
                    _self.StringBuilder.Append(empty);
                    _self.StringBuilder.Append((int)ac.P_VP);
                    _self.StringBuilder.Append(pct);
                    return _self.StringBuilder.ToString();
                case 22:
                    _self.StringBuilder.Append(language_table.GetData(109).Text);
                    _self.StringBuilder.Append(colon);
                    _self.StringBuilder.Append(empty);
                    _self.StringBuilder.Append((int)ac.M_VP);
                    _self.StringBuilder.Append(pct);
                    return _self.StringBuilder.ToString();
                case 23:
                    _self.StringBuilder.Append(language_table.GetData(114).Text);
                    _self.StringBuilder.Append(colon);
                    _self.StringBuilder.Append(empty);
                    _self.StringBuilder.Append((int)ac.EXP_R);
                    _self.StringBuilder.Append(pct);
                    return _self.StringBuilder.ToString();
            }

            return "";
        }

        private static void UpdateHeroSkill(this HeroInfoUI _self, bool _isNew)
        {
            var rc = _self.GetSceneChild<ResourcesComponent>();
            var uc = _self.GetChild<UnityObjectComponent>();
            if (rc == null || uc == null)
            {
                return;
            }

            var teamUI = _self.GetSceneChild<TeamUI>();
            var team = _self.GetSceneChild<Team>();
            var dc = _self.GetSceneChild<DataTableComponent>();
            if (teamUI == null || team == null || dc == null)
            {
                return;
            }

            string second = "s";

            var attribute_table = dc.LoadDataTable<DRAttribute>();
            var language_table = dc.LoadDataTable<DRLanguage>();
            var skill_table = dc.LoadDataTable<DRSkill>();
            var attribute_data = attribute_table.GetData(teamUI.SelectID);
            var hero = team.GetHero(attribute_data.ID);
            var sc = hero.GetChild<SkillComponent>();

            var transform_rect = _self.UIWindowBehaviour.GetTransform("Transform_Rect");
            for (int i = 0; i < transform_rect.childCount; i++)
            {
                var skill_item = transform_rect.GetChild(i);
                var info = skill_item.GetChild(0);
                var mask = skill_item.GetChild(1);
                var empty = skill_item.GetChild(2);

                var icon = info.GetChild(0).gameObject;
                var name = info.GetChild(1).gameObject;
                var description = info.GetChild(2).gameObject;
                var mp = info.GetChild(3).gameObject;
                var cd = info.GetChild(4).gameObject;


                if (i >= sc.SkillIDs.Count)
                {
                    info.gameObject.SetActive(false);
                    mask.gameObject.SetActive(false);
                    empty.gameObject.SetActive(true);
                    uc.Get<Image>(skill_item.gameObject).color = Graphics.COLOR_HIGH_GRAY;
                    uc.Get<TMP_Text>(empty.gameObject).text = language_table.GetData(128).Text;
                }
                else
                {
                    if (_isNew)
                    {
                        uc.Get<Image>(skill_item.gameObject).color = Graphics.COLOR_MORE_GRAY;

                        int skill_id = sc.SkillIDs[i];
                        var skill_data = skill_table.GetData(skill_id);

                        info.gameObject.SetActive(true);
                        if (!sc.IsLock(skill_id))
                        {
                            mask.gameObject.SetActive(false);
                        }
                        else
                        {
                            mask.gameObject.SetActive(true);
                            var tip = mask.GetChild(0).gameObject;
                            uc.Get<TMP_Text>(tip).text = string.Format(language_table.GetData(129).Text, skill_data.LockLV, skill_data.LockRANK);
                        }

                        empty.gameObject.SetActive(false);


                        rc.Assets.LoadAssetAsync<UnityEngine.Object>(skill_data.ABPath, skill_data.ABName, ResourceConfig.Extension.TEXTURE, _ =>
                        {
                            Sprite sprite = null;
                            if (_ is Texture2D t)
                            {
                                sprite = Sprite.Create(t, new Rect(0, 0, t.width, t.height), new Vector2(0.5f, 0.5f));
                            }

                            if (_ is Sprite s)
                            {
                                sprite = s;
                            }

                            uc.Get<Image>(icon).sprite = sprite;
                        });

                        uc.Get<TMP_Text>(name).text = skill_data.Name;
                        uc.Get<TMP_Text>(description).text = skill_data.Description;


                        float skill_cost = 0;
                        float skill_cd = 0;
                        switch (skill_data.Type)
                        {
                            case (int)eSkillType.Passive:

                                skill_cost = (float)sc.Skill_Cost(skill_id, false, (int)eAttribute.MP);
                                skill_cd = (float)sc.Skill_CD(skill_id, false);

                                uc.Get<TMP_Text>(cd).text = skill_data.Description;
                                break;
                            case (int)eSkillType.Active:
                            case (int)eSkillType.Both:
                                skill_cost = (float)sc.Skill_Cost(skill_id, true, (int)eAttribute.MP);
                                skill_cd = (float)sc.Skill_CD(skill_id, true);
                                uc.Get<TMP_Text>(mp).text = skill_data.Description;

                                break;
                        }

                        if (skill_cost == 0)
                        {
                            mp.gameObject.SetActive(false);
                        }
                        else
                        {
                            uc.Get<TMP_Text>(mp).text = skill_cost.ToString("F1");
                        }

                        if (skill_cd == 0)
                        {
                            cd.gameObject.SetActive(false);
                        }
                        else
                        {
                            uc.Get<TMP_Text>(cd).text = skill_cd.ToString("F1") + second;
                        }
                    }
                }
            }
        }
    }
}